<template>
  <div class="search-tab">
    <!-- 搜索栏 -->
    <el-form inline label-position="top" :show-message="false">
      <el-form-item v-for="prop in app.dataset.properties" :label="prop" :key="prop">
        <span slot="label">
          {{prop}}
          <i class="el-icon-delete" @click="handleDelete(query,[prop])"></i>
        </span>
        <el-input-number v-model="query[prop]" controls-position="right" :step="5" :min="0" :max="200" style="width: 115px"></el-input-number>
      </el-form-item>

      <!-- 机芯/数量 -->
      <el-form-item label="机芯/数量" v-for="(item,index) in otherQuery.group" :key="index">
        <span slot="label">
          机芯/数量
          <i class="el-icon-delete" @click="handleDelete(item,['name','value'])"></i>
        </span>
        <el-select v-model="item.name" style="width: 120px" clearable filterable placeholder="">
          <el-option v-for="option in handleNames(index)" :key="option" :label="option" :value="option"></el-option>
        </el-select>
        <el-input-number v-model="item.value" controls-position="right" step-strictly :min="1" :max="6" style="width: 74px"></el-input-number>
      </el-form-item>

      <el-form-item label="右机芯基本属性">
        <el-select v-model="otherQuery.rightMainProp" placeholder="" style="width: 120px">
          <el-option
            v-for="item in app.dataset.mainProps"
            :key="item"
            :label="item"
            :value="item">
          </el-option>
        </el-select>
      </el-form-item>

      <el-form-item label="重置/搜索">
        <el-button type="" icon="el-icon-refresh" @click="onReset"></el-button>
        <el-badge :value="res.length" :max="max" :hidden="!res.length" type="primary">
          <el-button type="primary" icon="el-icon-search" @click="onSearch" :loading="loading">
            <span v-if="time">{{time}}s</span>
            <el-tooltip v-if="res.length > max" placement="top" :open-delay="300" content="匹配的搜索结果超过了上限。一些更高属性的组合可能沒有被显示出來，若需要查看更多结果，请上调属性值">
              <i  class="el-icon-question"></i>
            </el-tooltip>
          </el-button>
        </el-badge>
      </el-form-item>
    </el-form>
    <!-- 搭配结果 -->
    <div class="table-group" v-infinite-scroll="loadMore" :infinite-scroll-distance="50">
      <el-empty v-if="!data.length"></el-empty>
      <el-card v-for="(group,index) in data" :key="index">
        <p style="line-height: 40px; text-align:center">
          <span style="float: left">
            {{index + 1}}、
            <span class="favorite" @click="favorite(group)">
              <span v-if="group.favorite">💙</span>
              <span v-else>🤍</span>
            </span>
          </span>
          <span v-if=" !(index % size)">
            <span>第{{Math.ceil((index+1)/size)}}页</span>/<span>共{{Math.ceil(res.length/size)}}页</span>
            <span>/ {{res.length}}</span>
          </span>
        </p>
        <l-table :data="group.data" :columns="columns" :header-cell-style="(data) => cellStyle(data,true)" :cell-style="cellStyle" show-summary :default-sort = "{prop: 'name', order: 'descending'}"></l-table>
      </el-card>
    </div>
  </div>
</template>

<script>
module.exports = {
  inject: ["app"],
  components: {
    LTable: httpVueLoader('./LTable.vue'),
  },
  data() {
    return {
      loading: false,
      query: {},
      otherQuery: {
        group: [{}, {}, {}],
        rightMainProp: '',
      },
      columns: [
        { label: "名称", prop: "name" },
        { label: "位置", prop: "direction" },
      ],
      headerStyle: { background: "#F5F7FA", color: "#555" },
      data: [],
      res: [],
      max: 50,
      page: 1,
      size: 10,
      time: 0,
    };
  },
  computed: {
    isGroup() {
      return Object.keys(this.need).length > 0;
    },
    need() {
      return this.otherQuery.group.reduce((need, item) => {
        if (item.name && item.value) {
          need[item.name] = item.value;
        }
        return need;
      }, {});
    },
    queryProps() {
      return Object.keys(this.query).filter((key) => this.query[key]);
    },
  },
  mounted() {
    this.columns = [
      ...this.columns,
      ...this.app.dataset.properties.map((v) => {
        return {
          label: v,
          prop: v,
        };
      }),
    ];
  },
  methods: {
    cellStyle({column}, isHeader = false) {
      if(this.query[column.property]) {
        return {
          background: '#F5F7FA',
          color: 'var(--primary)',
        }
      }
      return isHeader ? this.headerStyle : {};
    },
    handleDelete(data, keys) {
      keys.forEach((key) => {
        this.$delete(data, key);
      });
    },
    handleNames(index) {
      let hasName = this.otherQuery.group
        .filter((v, i) => i !== index && v.name)
        .map((v) => v.name);
      return this.app.dataset.names.filter(
        (name) => !hasName.includes(name)
      );
    },
    loadMore() {
      if (this.page * this.size >= this.res.length) return;
      this.data.push(
        ...this.res.slice(this.page++ * this.size, this.page * this.size)
      );
    },
    sum(list) {
      return list.reduce((sum, item) => {
        item.sum = +this.queryProps
          .reduce((res, prop) => {
            res += item[prop] || 0;
            return res;
          }, 0)
          .toFixed(1);
        sum += item.sum;
        return sum;
      }, 0);
    },
    onSearch() {
      if (!this.queryProps.length) {
        return this.$message.warning("至少查询一个属性搭配");
      }
      let startTime = Date.now();
      this.loading = true;
      this.page = 1;
      this.data = [];
      this.res = [];

      let res = [];
      let list = this.filterList();
      let length = this.isGroup
        ? this.otherQuery.group.reduce((total, item) => {
            total += item.value || 0;
            return total;
          }, 0)
        : 6;
      length = Math.min(6, length);
      // 深度优先
      res = this.$DFS(list, length, this.isGroup, this.need, this.max, this.valid);
      // 广度优化
      // res = this.$BFS(list, length, this.isGroup, this.need, this.max, this.valid);

      this.time = ((Date.now() - startTime) / 1000).toFixed(3);
      if (!res.length) this.$message.warning("未查询到装配组合");
      res.sort((a, b) => this.sum(b.data) - this.sum(a.data));
      this.res = res;
      this.data = res.slice(0, this.size);
      this.loading = false;
    },
    filterList() {
      return this.app.dataset.source.filter( c => {
        // 过滤右侧机芯属性
        if (this.otherQuery.rightMainProp && c.direction === '右' && c.mainProp !== this.otherQuery.rightMainProp) return false;
        // 过滤非指定机芯
        if(this.isGroup && !this.need[c.name]) return false;
        return true;
      })
    },
    backtrack(list, track, used, count, res, start, length) {
      if (this.valid(track)) {
        res.push({
          id: window.uuid(),
          favorite: false,
          data: [...track],
        });
      }

      if (track.length === length) return;

      for (let i = start; i < list.length; i++) {
        const c = list[i];
        if (res.length > this.max) return; // 组合太多了
        if (used[c.direction] === 2) continue; // 左 上 右 最多各 2个
        if(this.isGroup) {
          let cCount = count[c.name] || 0;
          if(cCount === this.need[c.name]) continue;// 不能大于指定数量
        }

        track.push(c);
        used[c.direction]++;
        count[c.name] = (count[c.name] || 0) + 1;
        this.backtrack(list, track, used, count, res, i + 1, length);
        used[c.direction]--;
        count[c.name]--
        track.pop();
      }
    },
    valid(list) {
      if (!list.length) return false;
      let res = {};
      for(let i = 0, prop; prop = this.queryProps[i++];) {
        for(let j = 0, item; item = list[j++];) {
          res[prop] = (res[prop] || 0) + (item[prop] || 0);
        }
        // 组合列表属性和小于 查询值
        if(res[prop] < this.query[prop]) return false;
      }
      return true;
    },
    onReset() {
      this.query = {};
      this.otherQuery = {
        group: [{}, {}, {}],
      };
      this.data = [];
      this.res = [];
      this.page = 1;
    },
    favorite(data){
      data.favorite = !data.favorite;
      let list = [...this.app.dataset.favorites];
      if(data.favorite) {
        list.push({
            ...data,
            cTime: Date.now(),
          });
      } else {
        list = list.filter( v => v.id !== data.id);
      }
      storage.updateFavorite(list);
      this.app.update()
    }
  },
}
</script>

<style scoped>
.table-group .el-card{
  margin-bottom: 20px;
}
</style>